<!DOCTYPE html><html lang="zh-Hans"><head><meta charset="utf-8"><title>Angular - 可观察对象（Observable）</title><meta name="Description" content="Angular is a platform for building mobile and desktop web applications.
    Join the community of millions of developers who build compelling user interfaces with Angular."><base href="/"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="search" type="application/opensearchdescription+xml" href="assets/opensearch.xml"><link rel="icon" type="image/x-icon" href="assets/images/favicons/favicon.ico"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-32x32.png" sizes="32x32"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-194x194.png" sizes="194x194"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-16x16.png" sizes="16x16"><link rel="apple-touch-icon" sizes="144x144" href="assets/images/favicons/favicon-144x144.png"><link rel="apple-touch-icon-precomposed" sizes="144x144" href="assets/images/favicons/favicon-144x144.png"><link href="assets/fonts/Material_Icons.css" rel="stylesheet"><link href="assets/fonts/Droid_Sans_Mono.css" rel="stylesheet"><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"><link rel="manifest" href="pwa-manifest.json"><meta name="theme-color" content="#1976d2"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="translucent"><script async="" src="assets/js/analytics.js"></script><script>!function(e,a,n,t,s,c,g){e.GoogleAnalyticsObject=s,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,c=a.createElement(n),g=a.getElementsByTagName(n)[0],c.async=1,c.src="assets/js/analytics.js",~e.name.indexOf("NG_DEFER_BOOTSTRAP")||g.parentNode.insertBefore(c,g)}(window,document,"script",0,"ga")</script><script>window.onerror=function(){ga("send","exception",{exDescription:function(e,r,n,a,c){var l;e=e.replace(/^Error: /,""),l=c?c.stack.replace(/^Error: /,"").replace(e+"\n","").replace(/^ +/gm,"").replace(/^at /gm,"").replace(/(?: \(|@)http.+\/([^/)]+)\)?(?:\n|$)/gm,"@$1\n").replace(/ *\(eval code(:\d+:\d+)\)(?:\n|$)/gm,"@???$1\n"):r+":"+(n=n||"?")+":"+(a=a||"?");return(e+"\n"+l).substr(0,150)}.apply(null,arguments),exFatal:!0})}</script><link rel="stylesheet" href="styles.4adbe52ad34df01b5273.css"><style>.cdk-high-contrast-active .mat-toolbar{outline:solid 1px}.mat-toolbar-row,.mat-toolbar-single-row{display:flex;box-sizing:border-box;padding:0 16px;width:100%;flex-direction:row;align-items:center;white-space:nowrap}.mat-toolbar-multiple-rows{display:flex;box-sizing:border-box;flex-direction:column;width:100%}.mat-toolbar-multiple-rows{min-height:64px}.mat-toolbar-row,.mat-toolbar-single-row{height:64px}@media(max-width:599px){.mat-toolbar-multiple-rows{min-height:56px}.mat-toolbar-row,.mat-toolbar-single-row{height:56px}}</style><style>.mat-icon{background-repeat:no-repeat;display:inline-block;fill:currentColor;height:24px;width:24px}.mat-icon.mat-icon-inline{font-size:inherit;height:inherit;line-height:inherit;width:inherit}[dir=rtl] .mat-icon-rtl-mirror{transform:scale(-1,1)}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon{display:block}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button .mat-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button .mat-icon{margin:auto}</style><style>.mat-button .mat-button-focus-overlay,.mat-icon-button .mat-button-focus-overlay{opacity:0}.mat-button:hover .mat-button-focus-overlay,.mat-stroked-button:hover .mat-button-focus-overlay{opacity:.04}@media(hover:none){.mat-button:hover .mat-button-focus-overlay,.mat-stroked-button:hover .mat-button-focus-overlay{opacity:0}}.mat-button,.mat-flat-button,.mat-icon-button,.mat-stroked-button{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible}.mat-button::-moz-focus-inner,.mat-flat-button::-moz-focus-inner,.mat-icon-button::-moz-focus-inner,.mat-stroked-button::-moz-focus-inner{border:0}.mat-button[disabled],.mat-flat-button[disabled],.mat-icon-button[disabled],.mat-stroked-button[disabled]{cursor:default}.mat-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-button.cdk-program-focused .mat-button-focus-overlay,.mat-flat-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-flat-button.cdk-program-focused .mat-button-focus-overlay,.mat-icon-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-icon-button.cdk-program-focused .mat-button-focus-overlay,.mat-stroked-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-stroked-button.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-button::-moz-focus-inner,.mat-flat-button::-moz-focus-inner,.mat-icon-button::-moz-focus-inner,.mat-stroked-button::-moz-focus-inner{border:0}.mat-raised-button{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible;transform:translate3d(0,0,0);transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1)}.mat-raised-button::-moz-focus-inner{border:0}.mat-raised-button[disabled]{cursor:default}.mat-raised-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-raised-button.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-raised-button::-moz-focus-inner{border:0}._mat-animation-noopable.mat-raised-button{transition:none;animation:none}.mat-stroked-button{border:1px solid currentColor;padding:0 15px;line-height:34px}.mat-stroked-button .mat-button-focus-overlay,.mat-stroked-button .mat-button-ripple.mat-ripple{top:-1px;left:-1px;right:-1px;bottom:-1px}.mat-fab{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible;transform:translate3d(0,0,0);transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1);min-width:0;border-radius:50%;width:56px;height:56px;padding:0;flex-shrink:0}.mat-fab::-moz-focus-inner{border:0}.mat-fab[disabled]{cursor:default}.mat-fab.cdk-keyboard-focused .mat-button-focus-overlay,.mat-fab.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-fab::-moz-focus-inner{border:0}._mat-animation-noopable.mat-fab{transition:none;animation:none}.mat-fab .mat-button-wrapper{padding:16px 0;display:inline-block;line-height:24px}.mat-mini-fab{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible;transform:translate3d(0,0,0);transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1);min-width:0;border-radius:50%;width:40px;height:40px;padding:0;flex-shrink:0}.mat-mini-fab::-moz-focus-inner{border:0}.mat-mini-fab[disabled]{cursor:default}.mat-mini-fab.cdk-keyboard-focused .mat-button-focus-overlay,.mat-mini-fab.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-mini-fab::-moz-focus-inner{border:0}._mat-animation-noopable.mat-mini-fab{transition:none;animation:none}.mat-mini-fab .mat-button-wrapper{padding:8px 0;display:inline-block;line-height:24px}.mat-icon-button{padding:0;min-width:0;width:40px;height:40px;flex-shrink:0;line-height:40px;border-radius:50%}.mat-icon-button .mat-icon,.mat-icon-button i{line-height:24px}.mat-button-focus-overlay,.mat-button-ripple.mat-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none;border-radius:inherit}.mat-button-ripple.mat-ripple:not(:empty){transform:translateZ(0)}.mat-button-focus-overlay{opacity:0;transition:opacity .2s cubic-bezier(.35,0,.25,1),background-color .2s cubic-bezier(.35,0,.25,1)}._mat-animation-noopable .mat-button-focus-overlay{transition:none}.cdk-high-contrast-active .mat-button-focus-overlay{background-color:#fff}.cdk-high-contrast-black-on-white .mat-button-focus-overlay{background-color:#000}.mat-button-ripple-round{border-radius:50%;z-index:1}.mat-button .mat-button-wrapper>*,.mat-fab .mat-button-wrapper>*,.mat-flat-button .mat-button-wrapper>*,.mat-icon-button .mat-button-wrapper>*,.mat-mini-fab .mat-button-wrapper>*,.mat-raised-button .mat-button-wrapper>*,.mat-stroked-button .mat-button-wrapper>*{vertical-align:middle}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button{display:block;font-size:inherit;width:2.5em;height:2.5em}.cdk-high-contrast-active .mat-button,.cdk-high-contrast-active .mat-fab,.cdk-high-contrast-active .mat-flat-button,.cdk-high-contrast-active .mat-icon-button,.cdk-high-contrast-active .mat-mini-fab,.cdk-high-contrast-active .mat-raised-button{outline:solid 1px}</style><style>.mat-drawer-container{position:relative;z-index:1;box-sizing:border-box;-webkit-overflow-scrolling:touch;display:block;overflow:hidden}.mat-drawer-container[fullscreen]{top:0;left:0;right:0;bottom:0;position:absolute}.mat-drawer-container[fullscreen].mat-drawer-container-has-open{overflow:hidden}.mat-drawer-container.mat-drawer-container-explicit-backdrop .mat-drawer-side{z-index:3}.mat-drawer-container.ng-animate-disabled .mat-drawer-backdrop,.mat-drawer-container.ng-animate-disabled .mat-drawer-content,.ng-animate-disabled .mat-drawer-container .mat-drawer-backdrop,.ng-animate-disabled .mat-drawer-container .mat-drawer-content{transition:none}.mat-drawer-backdrop{top:0;left:0;right:0;bottom:0;position:absolute;display:block;z-index:3;visibility:hidden}.mat-drawer-backdrop.mat-drawer-shown{visibility:visible}.mat-drawer-transition .mat-drawer-backdrop{transition-duration:.4s;transition-timing-function:cubic-bezier(.25,.8,.25,1);transition-property:background-color,visibility}.cdk-high-contrast-active .mat-drawer-backdrop{opacity:.5}.mat-drawer-content{position:relative;z-index:1;display:block;height:100%;overflow:auto}.mat-drawer-transition .mat-drawer-content{transition-duration:.4s;transition-timing-function:cubic-bezier(.25,.8,.25,1);transition-property:transform,margin-left,margin-right}.mat-drawer{position:relative;z-index:4;display:block;position:absolute;top:0;bottom:0;z-index:3;outline:0;box-sizing:border-box;overflow-y:auto;transform:translate3d(-100%,0,0)}.cdk-high-contrast-active .mat-drawer,.cdk-high-contrast-active [dir=rtl] .mat-drawer.mat-drawer-end{border-right:solid 1px currentColor}.cdk-high-contrast-active .mat-drawer.mat-drawer-end,.cdk-high-contrast-active [dir=rtl] .mat-drawer{border-left:solid 1px currentColor;border-right:none}.mat-drawer.mat-drawer-side{z-index:2}.mat-drawer.mat-drawer-end{right:0;transform:translate3d(100%,0,0)}[dir=rtl] .mat-drawer{transform:translate3d(100%,0,0)}[dir=rtl] .mat-drawer.mat-drawer-end{left:0;right:auto;transform:translate3d(-100%,0,0)}.mat-drawer-inner-container{width:100%;height:100%;overflow:auto;-webkit-overflow-scrolling:touch}.mat-sidenav-fixed{position:fixed}</style><style>.nav-link.highlight[_ngcontent-ng-docs-c30]{color:#ff0}</style><script charset="utf-8" src="toc-toc-module-es2015.f8531f591ee147aebcc6.js"></script><script charset="utf-8" src="default~code-code-example-module~code-code-tabs-module-es2015.9efcc76d2979a2e605e0.js"></script><script charset="utf-8" src="code-code-example-module-es2015.fa05e6f700453813d256.js"></script><style>.mat-progress-bar{display:block;height:4px;overflow:hidden;position:relative;transition:opacity 250ms linear;width:100%}._mat-animation-noopable.mat-progress-bar{transition:none;animation:none}.mat-progress-bar .mat-progress-bar-element,.mat-progress-bar .mat-progress-bar-fill::after{height:100%;position:absolute;width:100%}.mat-progress-bar .mat-progress-bar-background{width:calc(100% + 10px)}.cdk-high-contrast-active .mat-progress-bar .mat-progress-bar-background{display:none}.mat-progress-bar .mat-progress-bar-buffer{transform-origin:top left;transition:transform 250ms ease}.cdk-high-contrast-active .mat-progress-bar .mat-progress-bar-buffer{border-top:solid 5px;opacity:.5}.mat-progress-bar .mat-progress-bar-secondary{display:none}.mat-progress-bar .mat-progress-bar-fill{animation:none;transform-origin:top left;transition:transform 250ms ease}.cdk-high-contrast-active .mat-progress-bar .mat-progress-bar-fill{border-top:solid 4px}.mat-progress-bar .mat-progress-bar-fill::after{animation:none;content:"";display:inline-block;left:0}.mat-progress-bar[dir=rtl],[dir=rtl] .mat-progress-bar{transform:rotateY(180deg)}.mat-progress-bar[mode=query]{transform:rotateZ(180deg)}.mat-progress-bar[mode=query][dir=rtl],[dir=rtl] .mat-progress-bar[mode=query]{transform:rotateZ(180deg) rotateY(180deg)}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-fill,.mat-progress-bar[mode=query] .mat-progress-bar-fill{transition:none}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-primary,.mat-progress-bar[mode=query] .mat-progress-bar-primary{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-primary-indeterminate-translate 2s infinite linear;left:-145.166611%}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-primary.mat-progress-bar-fill::after,.mat-progress-bar[mode=query] .mat-progress-bar-primary.mat-progress-bar-fill::after{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-primary-indeterminate-scale 2s infinite linear}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-secondary,.mat-progress-bar[mode=query] .mat-progress-bar-secondary{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-secondary-indeterminate-translate 2s infinite linear;left:-54.888891%;display:block}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-secondary.mat-progress-bar-fill::after,.mat-progress-bar[mode=query] .mat-progress-bar-secondary.mat-progress-bar-fill::after{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-secondary-indeterminate-scale 2s infinite linear}.mat-progress-bar[mode=buffer] .mat-progress-bar-background{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-background-scroll 250ms infinite linear;display:block}.mat-progress-bar._mat-animation-noopable .mat-progress-bar-background,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-buffer,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-fill,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-fill::after,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-primary,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-primary.mat-progress-bar-fill::after,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-secondary,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-secondary.mat-progress-bar-fill::after{animation:none;transition:none}@keyframes mat-progress-bar-primary-indeterminate-translate{0%{transform:translateX(0)}20%{animation-timing-function:cubic-bezier(.5,0,.701732,.495819);transform:translateX(0)}59.15%{animation-timing-function:cubic-bezier(.302435,.381352,.55,.956352);transform:translateX(83.67142%)}100%{transform:translateX(200.611057%)}}@keyframes mat-progress-bar-primary-indeterminate-scale{0%{transform:scaleX(.08)}36.65%{animation-timing-function:cubic-bezier(.334731,.12482,.785844,1);transform:scaleX(.08)}69.15%{animation-timing-function:cubic-bezier(.06,.11,.6,1);transform:scaleX(.661479)}100%{transform:scaleX(.08)}}@keyframes mat-progress-bar-secondary-indeterminate-translate{0%{animation-timing-function:cubic-bezier(.15,0,.515058,.409685);transform:translateX(0)}25%{animation-timing-function:cubic-bezier(.31033,.284058,.8,.733712);transform:translateX(37.651913%)}48.35%{animation-timing-function:cubic-bezier(.4,.627035,.6,.902026);transform:translateX(84.386165%)}100%{transform:translateX(160.277782%)}}@keyframes mat-progress-bar-secondary-indeterminate-scale{0%{animation-timing-function:cubic-bezier(.15,0,.515058,.409685);transform:scaleX(.08)}19.15%{animation-timing-function:cubic-bezier(.31033,.284058,.8,.733712);transform:scaleX(.457104)}44.15%{animation-timing-function:cubic-bezier(.4,.627035,.6,.902026);transform:scaleX(.72796)}100%{transform:scaleX(.08)}}@keyframes mat-progress-bar-background-scroll{to{transform:translateX(-8px)}}</style><script charset="utf-8" src="assets-js-prettify-js-es2015.ba856648f2dd2d930a9b.js"></script></head><body><aio-shell ng-version="9.0.0-rc.11" class="aio-notification-hide folder-guide mode-stable page-guide-observables sidenav-open view-SideNav"><div id="top-of-page"></div><mat-toolbar color="primary" class="mat-toolbar app-toolbar no-print mat-primary mat-toolbar-multiple-rows"><mat-toolbar-row class="mat-toolbar-row notification-container"><aio-notification notificationid="survey-february-2019" expirationdate="2019-03-01" class="ng-tns-c22-0 ng-trigger ng-trigger-hideAnimation" style="height:0"><span class="content ng-tns-c22-0"><a href="http://bit.ly/angular-survey-2019" target="_blank" class="ng-tns-c22-0"><mat-icon role="img" svgicon="insert_comment" aria-label="Announcement" class="mat-icon notranslate icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></mat-icon><span class="message"><b>填写这份《一分钟调查》</b>，帮我们（开发组）做得更好！</span><span class="action-button">去填写</span></a></span><button mat-icon-button="" aria-label="Close" class="close-button ng-tns-c22-0 mat-icon-button mat-button-base"><span class="mat-button-wrapper"><mat-icon role="img" svgicon="close" aria-label="Dismiss notification" class="mat-icon notranslate mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></mat-icon></span><div matripple="" class="mat-ripple mat-button-ripple mat-button-ripple-round"></div><div class="mat-button-focus-overlay"></div></button></aio-notification></mat-toolbar-row><mat-toolbar-row class="mat-toolbar-row"><button mat-button="" title="Docs menu" class="hamburger mat-button mat-button-base"><span class="mat-button-wrapper"><mat-icon role="img" svgicon="menu" class="mat-icon notranslate mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></svg></mat-icon></span><div matripple="" class="mat-ripple mat-button-ripple"></div><div class="mat-button-focus-overlay"></div></button><a href="/" class="nav-link home"><img src="assets/images/logos/angular/logo-nav@2x.png" width="150" height="40" title="Home" alt="Home" class="ng-star-inserted"></a><aio-top-menu _nghost-ng-docs-c30="" class="ng-star-inserted"><ul _ngcontent-ng-docs-c30="" role="navigation"><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="features" title="特性" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">特性</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="docs" title="文档" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">文档</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="resources" title="资源" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">资源</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="events" title="会议" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">会议</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="https://blog.wangke.io/" title="译者汪志成的博客，包括翻译文章和原创文章" target="_blank"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">译者博客</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="translations/cn/home" title="关于中文版" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">关于中文版</span></a></li></ul></aio-top-menu><aio-search-box class="search-container"><input type="search" aria-label="search" placeholder="搜索"></aio-search-box><div class="toolbar-external-icons-container"><a href="https://twitter.com/angular" title="Twitter" aria-label="Angular on twitter"><mat-icon role="img" svgicon="logos:twitter" class="mat-icon notranslate mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 50 59" xmlns="http://www.w3.org/2000/svg"><path d="M50,9.3c-1.8,0.8-3.8,1.4-5.9,1.6c2.1-1.3,3.7-3.3,4.5-5.7c-2,1.2-4.2,2-6.5,2.5c-1.9-2-4.5-3.2-7.5-3.2c-5.7,0-10.3,4.6-10.3,10.3c0,0.8,0.1,1.6,0.3,2.3C16.1,16.7,8.5,12.6,3.5,6.4c-0.9,1.5-1.4,3.3-1.4,5.2c0,3.6,1.8,6.7,4.6,8.5C5,20,3.4,19.6,2,18.8c0,0,0,0.1,0,0.1c0,5,3.5,9.1,8.2,10.1c-0.9,0.2-1.8,0.4-2.7,0.4c-0.7,0-1.3-0.1-1.9-0.2c1.3,4.1,5.1,7,9.6,7.1c-3.5,2.8-7.9,4.4-12.7,4.4c-0.8,0-1.6,0-2.4-0.1c4.5,2.9,9.9,4.6,15.7,4.6c18.9,0,29.2-15.6,29.2-29.2c0-0.4,0-0.9,0-1.3C46.9,13.2,48.6,11.4,50,9.3z"></path></svg></mat-icon></a><a href="https://github.com/angular/angular" title="GitHub" aria-label="Angular on github"><mat-icon role="img" svgicon="logos:github" class="mat-icon notranslate mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 51.8 50.4" xmlns="http://www.w3.org/2000/svg"><path d="M25.9,0.2C11.8,0.2,0.3,11.7,0.3,25.8c0,11.3,7.3,20.9,17.5,24.3c1.3,0.2,1.7-0.6,1.7-1.2c0-0.6,0-2.6,0-4.8c-7.1,1.5-8.6-3-8.6-3c-1.2-3-2.8-3.7-2.8-3.7c-2.3-1.6,0.2-1.6,0.2-1.6c2.6,0.2,3.9,2.6,3.9,2.6c2.3,3.9,6,2.8,7.5,2.1c0.2-1.7,0.9-2.8,1.6-3.4c-5.7-0.6-11.7-2.8-11.7-12.7c0-2.8,1-5.1,2.6-6.9c-0.3-0.7-1.1-3.3,0.3-6.8c0,0,2.1-0.7,7,2.6c2-0.6,4.2-0.9,6.4-0.9c2.2,0,4.4,0.3,6.4,0.9c4.9-3.3,7-2.6,7-2.6c1.4,3.5,0.5,6.1,0.3,6.8c1.6,1.8,2.6,4.1,2.6,6.9c0,9.8-6,12-11.7,12.6c0.9,0.8,1.7,2.4,1.7,4.7c0,3.4,0,6.2,0,7c0,0.7,0.5,1.5,1.8,1.2c10.2-3.4,17.5-13,17.5-24.3C51.5,11.7,40.1,0.2,25.9,0.2z"></path></svg></mat-icon></a></div></mat-toolbar-row></mat-toolbar><mat-sidenav-container role="main" class="mat-drawer-container mat-sidenav-container sidenav-container mat-drawer-transition has-floating-toc"><div class="mat-drawer-backdrop ng-star-inserted"></div><div class="cdk-visually-hidden cdk-focus-trap-anchor" aria-hidden="true"></div><mat-sidenav tabindex="-1" class="mat-drawer mat-sidenav sidenav ng-tns-c18-1 ng-trigger ng-trigger-transform mat-drawer-side ng-star-inserted mat-drawer-opened" style="transform:none;visibility:visible"><div class="mat-drawer-inner-container ng-tns-c18-1"><aio-nav-menu class="ng-tns-c18-1"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="docs" title="Angular 文档简介" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="通过构建第一个 Angular 应用来学习基础知识" aria-pressed="false"><span>快速上手</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start" title="介绍 Angular 的组件模型、模板语法和组件通讯" target="_self"><span>你的第一个应用</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start/routing" title="介绍如何使用浏览器的 URL 在组件之间进行路由" target="_self"><span>路由</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start/data" title="介绍服务以及如何访问外部数据" target="_self"><span>管理数据</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start/forms" title="学习如何使用表单从用户那里获取并管理数据" target="_self"><span>表单</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start/deployment" title="通过你的应用放到 Firebase 或自己的服务器上来把它分享给外界" target="_self"><span>部署</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="guide/setup-local" title="使用 Angular CLI 搭建本地开发环境简介" target="_self"><span>搭建环境</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 expanded selected ng-star-inserted" title="Angular 的基本原理" aria-pressed="true"><span>基本原理</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 expanded selected"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="介绍 Angular 应用中的一些基本概念。" aria-pressed="false"><span>Angular 的基本概念</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture" title="Angular 应用中的基本构造块。" target="_self"><span>基本概念简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-modules" title="关于 Angular 模块（NgModules）。" target="_self"><span>模块简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-components" title="关于组件、模板和视图。" target="_self"><span>组件简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-services" title="关于服务与依赖注入。" target="_self"><span>服务与 DI 简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-next-steps" title="超越基础阶段。" target="_self"><span>后续步骤</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="英雄指南是这里大量 Angular 范例的基础" aria-pressed="false"><span>英雄指南</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial" title="《英雄指南》教程简介" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt0" title="创建应用的外壳" target="_self"><span>应用的“外壳”</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt1" title="第一部分：构建一个简单的英雄编辑器" target="_self"><span>1. 英雄编辑器</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt2" title="第二部分：构建一个主从结构的页面，用于展现英雄列表。" target="_self"><span>2. 显示英雄列表</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt3" title="第三部分：把主从结构的视图重构成几个独立的组件。" target="_self"><span>3. 创建特性组件</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt4" title="第四部分：创建一个可复用的服务来管理英雄数据。" target="_self"><span>4. 添加服务</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt5" title="第五部分：添加 Angular 路由器，并且学习在视图之间导航。" target="_self"><span>5. 添加应用内导航</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt6" title="第六部分：通过 HTTP 来获取并保存英雄数据。" target="_self"><span>6. 从服务器获取数据</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="通过数据绑定构建动态视图" aria-pressed="false"><span>组件与模板</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/displaying-data" title="属性绑定可以帮助应用把数据显示在界面上" target="_self"><span>显示数据</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/template-syntax" title="学习如何写模板，以便借助数据绑定机制显示数据并响应事件。" target="_self"><span>模板语法</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/user-input" title="用户输入会触发 DOM 事件。Angular 会通过事件绑定来监听那些事件，并把修改后的值传回应用的组件和模型中。" target="_self"><span>用户输入</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/lifecycle-hooks" title="Angular 调用指令和组件的生命周期钩子函数，包括它的创建、变更和销毁时。" target="_self"><span>生命周期钩子</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/component-interaction" title="在不同的指令和组件之间共享信息" target="_self"><span>组件交互</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/component-styles" title="添加专属于某个组件的样式" target="_self"><span>组件样式</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dynamic-component-loader" title="动态加载组件" target="_self"><span>动态组件</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/elements" title="把组件转换成自定义元素" target="_self"><span>Angular 元素</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/attribute-directives" title="属性型指令把行为添加到现有元素上。" target="_self"><span>属性型指令</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/structural-directives" title="结构型指令可以操纵页面的布局" target="_self"><span>结构型指令</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/pipes" title="管道可以在模板中转换显示的内容。" target="_self"><span>管道</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="Angular 的表单" aria-pressed="false"><span>表单</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/forms-overview" title="表单可以创建集中、高效、引人注目的输入体验。Angular 表单可以协调一组数据绑定控件，跟踪变更，验证输入，并表达错误信息。" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/reactive-forms" title="使用 FormBuilder、表单组和表单数组创建响应式表单。" target="_self"><span>响应式表单</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/forms" title="使用指令和 Angular 模板语法创建模板驱动表单。" target="_self"><span>模板驱动表单</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/form-validation" title="验证用户的表单输入" target="_self"><span>表单验证</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dynamic-form" title="使用 FormGroup 渲染动态表单。" target="_self"><span>动态表单</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 expanded selected ng-star-inserted" title="Observable 与 RxJS" aria-pressed="true"><span>Observable 与 RxJS</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 expanded selected"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 expanded selected ng-star-inserted" style="position:relative" href="guide/observables" title="" target="_self"><span>可观察对象(Observable)</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/rx-library" title="" target="_self"><span>RxJS 库</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/observables-in-angular" title="" target="_self"><span>Angular 中的可观察对象</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/practical-observable-usage" title="" target="_self"><span>用法实战</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/comparing-observables" title="" target="_self"><span>与其它技术的比较</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="Angular 中的模块" aria-pressed="false"><span>NgModules</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodules" title="使用 NgModule 让你的应用更高效" target="_self"><span>NgModule 简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodule-vs-jsmodule" title="JavaScript 模块和 NgModule 之间的差异" target="_self"><span>JS 模块 vs NgModule</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/bootstrapping" title="告诉 Angular 如何在根 &quot;AppModule&quot; 中构造和引导应用。" target="_self"><span>应用的根模块</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/frequent-ngmodules" title="介绍最常用的 NgModule" target="_self"><span>常用模块</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/module-types" title="介绍特性模块的几种类型" target="_self"><span>特性模块的分类</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/entry-components" title="关于 Angular 中入口组件的一切" target="_self"><span>入口组件</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/feature-modules" title="创建特性模块，以组织你的代码" target="_self"><span>特性模块</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/providers" title="服务提供者与 NgModule" target="_self"><span>服务提供者</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/singleton-services" title="创建单例服务" target="_self"><span>单例服务</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/lazy-loading-ngmodules" title="惰性加载模块，以提高应用的性能" target="_self"><span>惰性加载的特性模块</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/sharing-ngmodules" title="共享 NgModule 让你的应用现代化。" target="_self"><span>共享 NgModule</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodule-api" title="理解 NgModule 的那些细节。" target="_self"><span>NgModule API</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodule-faq" title="回答关于 NgModules 的常见问题。" target="_self"><span>NgModule 常见问题</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="依赖注入：创建并注入各种服务。" aria-pressed="false"><span>依赖注入</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection" title="Angular 的依赖注入系统能够为 Angular 创建的类创建并交付它们所依赖的服务。" target="_self"><span>Angular 依赖注入</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/hierarchical-dependency-injection" title="与组件树平行的注入器树，并支持嵌套的依赖。" target="_self"><span>多级注入器</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection-providers" title="各种提供者类型的更多知识。" target="_self"><span>DI 提供者</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection-in-action" title="依赖注入的使用技巧" target="_self"><span>DI 实战</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection-navtree" title="使用注入器树来查找父组件。" target="_self"><span>浏览组件树</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/http" title="通过 HTTP 协议与远程服务器对话。" target="_self"><span>HttpClient</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/router" title="揭示如何通过 Angular 路由进行基本的屏幕导航。" target="_self"><span>路由与导航</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="Angular 动画系统指南" aria-pressed="false"><span>动画</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/animations" title="Angular 动画的基础技术。" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/transition-and-triggers" title="转场与触发器的高级技术。" target="_self"><span>转场与触发器</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/complex-animation-sequences" title="复杂的 Angular 动画序列。" target="_self"><span>复杂序列</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/reusable-animations" title="创建可复用的动画。" target="_self"><span>可复用动画</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/route-animations" title="为路由提供转场动画。" target="_self"><span>路由转场动画</span></a></div></aio-nav-item></div></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="把 Angular 用到你的实际工作中的一些技巧" aria-pressed="false"><span>其它技术</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/security" title="Angular 应用开发中的安全技术。" target="_self"><span>安全</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/i18n" title="把应用模板中的文本翻译成多种语言。" target="_self"><span>国际化（i18n）</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/accessibility" title="设计能被所有用户访问的应用" target="_self"><span>无障碍（a11y）</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="Angular Service Worker: 控制应用资源的缓存。" aria-pressed="false"><span>Service Worker 与 PWA</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-intro" title="Angular 对 Service Worker 的实现提升了慢速或不稳定的网络连接下的用户体验。" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-getting-started" title="在 CLI 项目中启用 Service Worker，并在浏览器中查看效果。" target="_self"><span>快速上手</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/app-shell" title="在 CLI 项目中启用应用外壳。" target="_self"><span>应用外壳</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-communications" title="那些能让你和 Angular 的 Service Worker 通讯的服务类。" target="_self"><span>与 Service Worker 通讯</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-devops" title="使用 Service Worker 运行应用、管理应用更新、调试以及杀掉正在运行的应用。" target="_self"><span>生产环境下的 Service Worker</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-config" title="配置 Service Worker 的缓存行为。" target="_self"><span>Service Worker 配置</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/universal" title="使用 Angular Universal 在服务端渲染 HTML。" target="_self"><span>服务端渲染</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="把 AngularJS 应用增量式的升级到 Angular。" aria-pressed="false"><span>从 AngularJS 升级</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/upgrade" title="把 AngularJS 应用增量式的升级到 Angular。" target="_self"><span>升级步骤</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/upgrade-performance" title="用更灵活的方式把 AngularJS 升级到 Angular。" target="_self"><span>更关注性能的升级方式</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ajs-quick-reference" title="学习如何把 AngularJS 的概念映射到 Angular 中。" target="_self"><span>AngularJS 与 Angular 的概念对照</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="使用共享库扩展 Angular" aria-pressed="false"><span>开发 Angular 库</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/libraries" title="理解何时以及如何使用和创建库。" target="_self"><span>库概览</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/using-libraries" title="把已发布的库集成进你的应用中。" target="_self"><span>使用已发布的库</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/creating-libraries" title="通过创建、发布和使用你自己的库来扩展 Angular。" target="_self"><span>创建库</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="理解原理图" aria-pressed="false"><span>原理图（Schematic）</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/schematics" title="理解 Angular 如何使用原理图。" target="_self"><span>原理图概览</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/schematics-authoring" title="理解原理图的结构。" target="_self"><span>制作原理图</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/schematics-for-libraries" title="使用原理图来把你的库集成进 Angular CLI 中。" target="_self"><span>库的原理图</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/cli-builder" title="使用构建器定制 Angular CLI。" target="_self"><span>CLI 构建器</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/web-worker" title="在 Angular CLI 中使用 Web Worker。" target="_self"><span>Web Worker</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="关于构建、测试和部署的信息" aria-pressed="false"><span>开发工作流</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="理解 AOT 预先编译器。" aria-pressed="false"><span>AOT 预先编译器</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/aot-compiler" title="学习为何以及如何使用预先编译器。" target="_self"><span>预先编译</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/angular-compiler-options" title="配置 AOT 编译。" target="_self"><span>Angular 编译器选项</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/aot-metadata-errors" title="解决 AOT 编译错误。" target="_self"><span>AOT 元数据错误</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/template-typecheck" title="Angular 中的模板类型检查。" target="_self"><span>模板类型检查</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/build" title="构建应用及为应用启动开发服务器。" target="_self"><span>构建与运行</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/bazel" title="如何配置你的环境，以利用 Bazel 进行构建和测试。" target="_self"><span>使用 Bazel 进行构建</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/testing" title="测试 Angular 应用的技巧与实践。" target="_self"><span>测试</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/deployment" title="了解如何部署 Angular 应用。" target="_self"><span>发布</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="与开发环境和工具集成起来" aria-pressed="false"><span>开发工具集成</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/language-service" title="使用 Angular 语言服务加速开发。" target="_self"><span>语言服务</span></a></div></aio-nav-item></div></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="工作空间与项目的结构，及其配置文件。" aria-pressed="false"><span>配置</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/file-structure" title="Angular 工作区在文件系统中是怎样的。" target="_self"><span>项目文件结构</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/workspace-config" title="&quot;angular.json&quot; 包含供 CLI 命令使用的工作区和项目默认配置。" target="_self"><span>工作区配置</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/npm-packages" title="开发期间和运行期间所需的 npm 包的说明。" target="_self"><span>npm 包</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/typescript-configuration" title="给 Angular 开发者的 TypeScript 配置。" target="_self"><span>TypeScript 配置</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/browser-support" title="浏览器支持与腻子脚本指南。" target="_self"><span>浏览器支持</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="Angular 的版本发布实践、更新与升级。" aria-pressed="false"><span>发布信息</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/updating" title="如何把 Angular 应用和库升级到最新版本。" target="_self"><span>保持最新</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/releases" title="Angular 的版本、发布、支持、弃用策略及实践。" target="_self"><span>发布实践</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/updating-to-version-9" title="支持把你的应用从 8 升级到 9。" target="_self"><span>升级到第 9 版</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/deprecations" title="弃用的 Angular API 和特性汇总。" target="_self"><span>弃用清单</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/ivy" title="关于 Angular Ivy 的编译与渲染管道。" target="_self"><span>Angular Ivy</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="Angular 语法、编码、术语汇总。" aria-pressed="false"><span>快捷手册</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/cheatsheet" title="关于 Angular 常用编码技术的快速指南。" target="_self"><span>速查表</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/styleguide" title="写出 Angular 风格的程序" target="_self"><span>风格指南</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/glossary" title="Angular 中最重要的词汇的简要定义。" target="_self"><span>词汇表</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="Angular CLI 命令参考手册。" aria-pressed="false"><span>CLI 命令</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli" title="CLI 工具介绍、命令、语法" target="_self"><span>概览</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/usage-analytics-gathering" title="管理员如何从用户那里收集使用情况分析。" target="_self"><span>使用情况分析</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/add" title="ng add." target="_self"><span>ng add</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/analytics" title="ng analytics." target="_self"><span>ng analytics</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/build" title="ng build." target="_self"><span>ng build</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/config" title="ng config." target="_self"><span>ng config</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/deploy" title="ng deploy." target="_self"><span>ng deploy</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/doc" title="ng doc." target="_self"><span>ng doc</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/e2e" title="ng e2e." target="_self"><span>ng e2e</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/generate" title="ng generate." target="_self"><span>ng generate</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/help" title="ng help." target="_self"><span>ng help</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/lint" title="ng lint." target="_self"><span>ng lint</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/new" title="ng new." target="_self"><span>ng new</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/run" title="ng run." target="_self"><span>ng run</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/serve" title="ng serve." target="_self"><span>ng serve</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/test" title="ng test." target="_self"><span>ng test</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/update" title="ng update." target="_self"><span>ng update</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/version" title="ng version." target="_self"><span>ng version</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/xi18n" title="ng xi18n." target="_self"><span>ng xi18n</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="api" title="关于 Angular 中类和值的详细信息。" target="_self"><span>API 参考手册</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><div class="mat-divider ng-star-inserted" style="margin:4px 20px;border-top:1px solid #d3d3d3"></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://github.com/ng-docs/ng-docs.github.io/issues" title="github 上的中文互助问答区" target="_blank"><span>互助问答</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://material.angular.cn" title="Angular Material 组件库的中文文档" target="_blank"><span>官方 Material 组件库</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://ng.ant.design/" title="Ant Design 的 Angular 实现，服务于企业级后台产品。" target="_blank"><span>ng-zorro 组件库</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://devui.design/" title="“华为云” 开源的企业级组件库，核心设计思想是：致简、沉浸、灵活" target="_blank"><span>华为 DevUI 组件库</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://ng.mobile.ant.design/" title="Ant Design Mobile 的 Angular 实现，服务于无线产品。" target="_blank"><span>ng-zorro mobile 组件库</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://flutter.cn/" title="Flutter 中文文档站" target="_blank"><span>友站：Flutter 中文</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item></aio-nav-menu><div class="doc-version ng-tns-c18-1"><aio-select><div class="form-select-menu"><button class="form-select-button"><span><strong></strong></span><span>stable (v9.0.0)</span></button></div></aio-select></div></div></mat-sidenav><div class="cdk-visually-hidden cdk-focus-trap-anchor" aria-hidden="true"></div><mat-sidenav-content cdkscrollable="" class="mat-drawer-content mat-sidenav-content ng-star-inserted" style="margin-left:261px"><main role="main" class="sidenav-content" id="guide-observables"><aio-mode-banner></aio-mode-banner><aio-doc-viewer class=""><div style="opacity:1"><div class="github-links"><a href="https://github.com/angular/angular-cn/edit/aio/aio/content/guide/observables.md?message=docs%3A%20请简述你的修改..." aria-label="提供编辑建议" title="提供编辑建议"><i class="material-icons" aria-hidden="true" role="img">mode_edit</i></a></div><div class="content"><h1 id="observables" translation-result="on">可观察对象（Observable）<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#observables"><i class="material-icons">link</i></a></h1><aio-toc class="embedded" ng-version="9.0.0-rc.11"><div class="toc-inner no-print collapsed ng-star-inserted"><button type="button" title="Expand/collapse contents" aria-label="Expand/collapse contents" class="toc-heading embedded secondary ng-star-inserted" aria-pressed="false">目录<mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon collapsed mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><ul class="toc-list embedded"><li class="h2 ng-star-inserted" title="基本用法和词汇"><a href="guide/observables#basic-usage-and-terms">基本用法和词汇</a></li><li class="h2 ng-star-inserted" title="定义观察者"><a href="guide/observables#defining-observers">定义观察者</a></li><li class="h2 ng-star-inserted" title="订阅"><a href="guide/observables#subscribing">订阅</a></li><li class="h2 secondary ng-star-inserted" title="创建可观察对象"><a href="guide/observables#creating-observables">创建可观察对象</a></li><li class="h2 secondary ng-star-inserted" title="多播"><a href="guide/observables#multicasting">多播</a></li><li class="h2 secondary ng-star-inserted" title="错误处理"><a href="guide/observables#error-handling">错误处理</a></li></ul><button type="button" title="Expand/collapse contents" aria-label="Expand/collapse contents" class="toc-more-items embedded material-icons collapsed ng-star-inserted" aria-pressed="false"></button></div></aio-toc><h1 translation-origin="off" id="observables">Observables<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#observables"><i class="material-icons">link</i></a></h1><p translation-result="on">可观察对象支持在应用中的发布者和订阅者之间传递消息。 在需要进行事件处理、异步编程和处理多个值的时候，可观察对象相对其它技术有着显著的优点。</p><p translation-origin="off">Observables provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values.</p><p translation-result="on">可观察对象是声明式的 —— 也就是说，虽然你定义了一个用于发布值的函数，但是在有消费者订阅它之前，这个函数并不会实际执行。 订阅之后，当这个函数执行完或取消订阅时，订阅者就会收到通知。</p><p translation-origin="off">Observables are declarative—that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or until they unsubscribe.</p><p translation-result="on">可观察对象可以发送多个任意类型的值 —— 字面量、消息、事件。无论这些值是同步发送的还是异步发送的，接收这些值的 API 都是一样的。 由于准备（setup）和清场（teardown）的逻辑都是由可观察对象自己处理的，因此你的应用代码只管订阅并消费这些值就可以了，做完之后，取消订阅。无论这个流是击键流、HTTP 响应流还是定时器，对这些值进行监听和停止监听的接口都是一样的。</p><p translation-origin="off">An observable can deliver multiple values of any type—literals, messages, or events, depending on the context. The API for receiving values is the same whether the values are delivered synchronously or asynchronously. Because setup and teardown logic are both handled by the observable, your application code only needs to worry about subscribing to consume values, and when done, unsubscribing. Whether the stream was keystrokes, an HTTP response, or an interval timer, the interface for listening to values and stopping listening is the same.</p><p translation-result="on">由于这些优点，可观察对象在 Angular 中得到广泛使用，也同样建议应用开发者好好使用它。</p><p translation-origin="off">Because of these advantages, observables are used extensively within Angular, and are recommended for app development as well.</p><h2 id="basic-usage-and-terms" translation-result="on">基本用法和词汇<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#basic-usage-and-terms"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="basic-usage-and-terms">Basic usage and terms<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#basic-usage-and-terms"><i class="material-icons">link</i></a></h2><p translation-result="on">作为发布者，你创建一个 <code>Observable</code> 的实例，其中定义了一个<em>订阅者（subscriber）</em>函数。 当有消费者调用 <code>subscribe()</code> 方法时，这个函数就会执行。 订阅者函数用于定义“如何获取或生成那些要发布的值或消息”。</p><p translation-origin="off">As a publisher, you create an <code>Observable</code> instance that defines a <em>subscriber</em> function. This is the function that is executed when a consumer calls the <code>subscribe()</code> method. The subscriber function defines how to obtain or generate values or messages to be published.</p><p translation-result="on">要执行所创建的可观察对象，并开始从中接收通知，你就要调用它的 <code>subscribe()</code> 方法，并传入一个<em>观察者（observer）</em>。 这是一个 JavaScript 对象，它定义了你收到的这些消息的处理器（handler）。 <code>subscribe()</code> 调用会返回一个 <code>Subscription</code> 对象，该对象具有一个 <code><a href="api/service-worker/SwPush#unsubscribe" class="code-anchor">unsubscribe()</a></code> 方法。 当调用该方法时，你就会停止接收通知。</p><p translation-origin="off">To execute the observable you have created and begin receiving notifications, you call its <code>subscribe()</code> method, passing an <em>observer</em>. This is a JavaScript object that defines the handlers for the notifications you receive. The <code>subscribe()</code> call returns a <code>Subscription</code> object that has an <code><a href="api/service-worker/SwPush#unsubscribe" class="code-anchor">unsubscribe()</a></code> method, which you call to stop receiving notifications.</p><p translation-result="on">下面这个例子中示范了这种基本用法，它展示了如何使用可观察对象来对当前地理位置进行更新。</p><p translation-origin="off">Here's an example that demonstrates the basic usage model by showing how an observable could be used to provide geolocation updates.</p><code-example class="no-auto-link" path="observables/src/geolocation.ts" header="Observe geolocation updates" ng-version="9.0.0-rc.11"><div style="display:none">// Create an Observable that will start listening to geolocation updates // when a consumer subscribes. const locations = new Observable((observer) =&gt; { let watchId: number; // Simple geolocation API check provides values to publish if ('geolocation' in navigator) { watchId = navigator.geolocation.watchPosition((position: Position) =&gt; { observer.next(position); }, (error: PositionError) =&gt; { observer.error(error); }); } else { observer.error('Geolocation not available'); } // When the consumer unsubscribes, clean up data ready for next subscription. return { unsubscribe() { navigator.geolocation.clearWatch(watchId); } }; }); // Call subscribe() to start listening for updates. const locationsSubscription = locations.subscribe({ next(position) { console.log('Current Position: ', position); }, error(msg) { console.log('Error Getting Location: ', msg); } }); // Stop listening for location after 10 seconds setTimeout(() =&gt; { locationsSubscription.unsubscribe(); }, 10000);</div><header class="ng-star-inserted">Observe geolocation updates</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from Observe geolocation updates">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// Create an Observable that will start listening to geolocation updates</span><span class="pln">
</span><span class="com">// when a consumer subscribes.</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> locations </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Observable</span><span class="pun">((</span><span class="pln">observer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> watchId</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// Simple geolocation API check provides values to publish</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="str">'geolocation'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> navigator</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    watchId </span><span class="pun">=</span><span class="pln"> navigator</span><span class="pun">.</span><span class="pln">geolocation</span><span class="pun">.</span><span class="pln">watchPosition</span><span class="pun">((</span><span class="pln">position</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Position</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      observer</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="pln">position</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln"> </span><span class="pun">(</span><span class="pln">error</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PositionError</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      observer</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    observer</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="str">'Geolocation not available'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// When the consumer unsubscribes, clean up data ready for next subscription.</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    unsubscribe</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      navigator</span><span class="pun">.</span><span class="pln">geolocation</span><span class="pun">.</span><span class="pln">clearWatch</span><span class="pun">(</span><span class="pln">watchId</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="com">// Call subscribe() to start listening for updates.</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> locationsSubscription </span><span class="pun">=</span><span class="pln"> locations</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">({</span><span class="pln">
  </span><span class="kwd">next</span><span class="pun">(</span><span class="pln">position</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Current Position: '</span><span class="pun">,</span><span class="pln"> position</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  error</span><span class="pun">(</span><span class="pln">msg</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Error Getting Location: '</span><span class="pun">,</span><span class="pln"> msg</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="com">// Stop listening for location after 10 seconds</span><span class="pln">
setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  locationsSubscription</span><span class="pun">.</span><span class="pln">unsubscribe</span><span class="pun">();</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="lit">10000</span><span class="pun">);</span></code>
    </pre></aio-code></code-example><h2 id="defining-observers" translation-result="on">定义观察者<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#defining-observers"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="defining-observers">Defining observers<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#defining-observers"><i class="material-icons">link</i></a></h2><p translation-result="on">用于接收可观察对象通知的处理器要实现 <code>Observer</code> 接口。这个对象定义了一些回调函数来处理可观察对象可能会发来的三种通知：</p><p translation-origin="off">A handler for receiving observable notifications implements the <code>Observer</code> interface. It is an object that defines callback methods to handle the three types of notifications that an observable can send:</p><table><thead><tr><th align="left"><p translation-result="on">通知类型</p><p translation-origin="off">Notification type</p></th><th align="left"><p translation-result="on">说明</p><p translation-origin="off">Description</p></th></tr></thead><tbody><tr><td align="left"><code>next</code></td><td align="left"><p translation-result="on">必要。用来处理每个送达值。在开始执行后可能执行零次或多次。</p><p translation-origin="off">Required. A handler for each delivered value. Called zero or more times after execution starts.</p></td></tr><tr><td align="left"><code>error</code></td><td align="left"><p translation-result="on">可选。用来处理错误通知。错误会中断这个可观察对象实例的执行过程。</p><p translation-origin="off">Optional. A handler for an error notification. An error halts execution of the observable instance.</p></td></tr><tr><td align="left"><code>complete</code></td><td align="left"><p translation-result="on">可选。用来处理执行完毕（complete）通知。当执行完毕后，这些值就会继续传给下一个处理器。</p><p translation-origin="off">Optional. A handler for the execution-complete notification. Delayed values can continue to be delivered to the next handler after execution is complete.</p></td></tr></tbody></table><p translation-result="on">观察者对象可以定义这三种处理器的任意组合。如果你不为某种通知类型提供处理器，这个观察者就会忽略相应类型的通知。</p><p translation-origin="off">An observer object can define any combination of these handlers. If you don't supply a handler for a notification type, the observer ignores notifications of that type.</p><h2 id="subscribing" translation-result="on">订阅<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#subscribing"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="subscribing">Subscribing<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#subscribing"><i class="material-icons">link</i></a></h2><p translation-result="on">只有当有人订阅 <code>Observable</code> 的实例时，它才会开始发布值。 订阅时要先调用该实例的 <code>subscribe()</code> 方法，并把一个观察者对象传给它，用来接收通知。</p><p translation-origin="off">An <code>Observable</code> instance begins publishing values only when someone subscribes to it. You subscribe by calling the <code>subscribe()</code> method of the instance, passing an observer object to receive the notifications.</p><div class="alert is-helpful"><p translation-result="on">为了展示订阅的原理，我们需要创建新的可观察对象。它有一个构造函数可以用来创建新实例，但是为了更简明，也可以使用 <code>Observable</code> 上定义的一些静态方法来创建一些常用的简单可观察对象：</p><p translation-origin="off">In order to show how subscribing works, we need to create a new observable. There is a constructor that you use to create new instances, but for illustration, we can use some methods from the RxJS library that create simple observables of frequently used types:</p><ul><li><p translation-result="on"> <code>of(...items)</code> —— 返回一个 <code>Observable</code> 实例，它用同步的方式把参数中提供的这些值发送出来。</p><p translation-origin="off"><code>of(...items)</code>—Returns an <code>Observable</code> instance that synchronously delivers the values provided as arguments.</p></li><li><p translation-result="on"> <code>from(iterable)</code> —— 把它的参数转换成一个 <code>Observable</code> 实例。 该方法通常用于把一个数组转换成一个（发送多个值的）可观察对象。</p><p translation-origin="off"><code>from(iterable)</code>—Converts its argument to an <code>Observable</code> instance. This method is commonly used to convert an array to an observable.</p></li></ul></div><p translation-result="on">下面的例子会创建并订阅一个简单的可观察对象，它的观察者会把接收到的消息记录到控制台中：</p><p translation-origin="off">Here's an example of creating and subscribing to a simple observable, with an observer that logs the received message to the console:</p><code-example path="observables/src/subscribing.ts" region="observer" header="Subscribe using observer" ng-version="9.0.0-rc.11"><div style="display:none">// Create simple observable that emits three values const myObservable = of(1, 2, 3); // Create observer object const myObserver = { next: x =&gt; console.log('Observer got a next value: ' + x), error: err =&gt; console.error('Observer got an error: ' + err), complete: () =&gt; console.log('Observer got a complete notification'), }; // Execute with the observer object myObservable.subscribe(myObserver); // Logs: // Observer got a next value: 1 // Observer got a next value: 2 // Observer got a next value: 3 // Observer got a complete notification</div><header class="ng-star-inserted">Subscribe using observer</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from Subscribe using observer">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// Create simple observable that emits three values</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> myObservable </span><span class="pun">=</span><span class="pln"> of</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">);</span><span class="pln">

</span><span class="com">// Create observer object</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> myObserver </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">next</span><span class="pun">:</span><span class="pln"> x </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Observer got a next value: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x</span><span class="pun">),</span><span class="pln">
  error</span><span class="pun">:</span><span class="pln"> err </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="str">'Observer got an error: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> err</span><span class="pun">),</span><span class="pln">
  complete</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Observer got a complete notification'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="com">// Execute with the observer object</span><span class="pln">
myObservable</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">(</span><span class="pln">myObserver</span><span class="pun">);</span><span class="pln">
</span><span class="com">// Logs:</span><span class="pln">
</span><span class="com">// Observer got a next value: 1</span><span class="pln">
</span><span class="com">// Observer got a next value: 2</span><span class="pln">
</span><span class="com">// Observer got a next value: 3</span><span class="pln">
</span><span class="com">// Observer got a complete notification</span></code>
    </pre></aio-code></code-example><p translation-result="on">另外，<code>subscribe()</code> 方法还可以接收定义在同一行中的回调函数，无论 <code>next</code>、<code>error</code> 还是 <code>complete</code> 处理器。比如，下面的 <code>subscribe()</code> 调用和前面指定预定义观察者的例子是等价的。</p><p translation-origin="off">Alternatively, the <code>subscribe()</code> method can accept callback function definitions in line, for <code>next</code>, <code>error</code>, and <code>complete</code> handlers. For example, the following <code>subscribe()</code> call is the same as the one that specifies the predefined observer:</p><code-example path="observables/src/subscribing.ts" region="sub_fn" header="Subscribe with positional arguments" ng-version="9.0.0-rc.11"><div style="display:none">myObservable.subscribe( x =&gt; console.log('Observer got a next value: ' + x), err =&gt; console.error('Observer got an error: ' + err), () =&gt; console.log('Observer got a complete notification') );</div><header class="ng-star-inserted">Subscribe with positional arguments</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from Subscribe with positional arguments">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">myObservable</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">(</span><span class="pln">
  x </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Observer got a next value: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> x</span><span class="pun">),</span><span class="pln">
  err </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="str">'Observer got an error: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> err</span><span class="pun">),</span><span class="pln">
  </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Observer got a complete notification'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></code>
    </pre></aio-code></code-example><p translation-result="on">无论哪种情况，<code>next</code> 处理器都是必要的，而 <code>error</code> 和 <code>complete</code> 处理器是可选的。</p><p translation-origin="off">In either case, a <code>next</code> handler is required. The <code>error</code> and <code>complete</code> handlers are optional.</p><p translation-result="on">注意，<code>next()</code> 函数可以接受消息字符串、事件对象、数字值或各种结构，具体类型取决于上下文。 为了更通用一点，我们把由可观察对象发布出来的数据统称为<em>流</em>。任何类型的值都可以表示为可观察对象，而这些值会被发布为一个流。</p><p translation-origin="off">Note that a <code>next()</code> function could receive, for instance, message strings, or event objects, numeric values, or structures, depending on context. As a general term, we refer to data published by an observable as a <em>stream</em>. Any type of value can be represented with an observable, and the values are published as a stream.</p><h2 id="creating-observables" translation-result="on">创建可观察对象<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#creating-observables"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="creating-observables">Creating observables<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#creating-observables"><i class="material-icons">link</i></a></h2><p translation-result="on">使用 <code>Observable</code> 构造函数可以创建任何类型的可观察流。 当执行可观察对象的 <code>subscribe()</code> 方法时，这个构造函数就会把它接收到的参数作为订阅函数来运行。 订阅函数会接收一个 <code>Observer</code> 对象，并把值发布给观察者的 <code>next()</code> 方法。</p><p translation-origin="off">Use the <code>Observable</code> constructor to create an observable stream of any type. The constructor takes as its argument the subscriber function to run when the observable’s <code>subscribe()</code> method executes. A subscriber function receives an <code>Observer</code> object, and can publish values to the observer's <code>next()</code> method.</p><p translation-result="on">比如，要创建一个与前面的 <code>of(1, 2, 3)</code> 等价的可观察对象，你可以这样做：</p><p translation-origin="off">For example, to create an observable equivalent to the <code>of(1, 2, 3)</code> above, you could do something like this:</p><code-example path="observables/src/creating.ts" region="subscriber" header="Create observable with constructor" ng-version="9.0.0-rc.11"><div style="display:none">// This function runs when subscribe() is called function sequenceSubscriber(observer) { // synchronously deliver 1, 2, and 3, then complete observer.next(1); observer.next(2); observer.next(3); observer.complete(); // unsubscribe function doesn't need to do anything in this // because values are delivered synchronously return {unsubscribe() {}}; } // Create a new Observable that will deliver the above <a href="api/animations/sequence" class="code-anchor">sequence</a> const <a href="api/animations/sequence" class="code-anchor">sequence</a> = new Observable(sequenceSubscriber); // execute the Observable and print the result of each notification sequence.subscribe({ next(num) { console.log(num); }, complete() { console.log('<a href="" class="code-anchor">Finished</a> <a href="api/animations/sequence" class="code-anchor">sequence</a>'); } }); // Logs: // 1 // 2 // 3 // <a href="" class="code-anchor">Finished</a> <a href="api/animations/sequence" class="code-anchor">sequence</a></div><header class="ng-star-inserted">Create observable with constructor</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from Create observable with constructor">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// This function runs when subscribe() is called</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> sequenceSubscriber</span><span class="pun">(</span><span class="pln">observer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// synchronously deliver 1, 2, and 3, then complete</span><span class="pln">
  observer</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  observer</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span><span class="pln">
  observer</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln">
  observer</span><span class="pun">.</span><span class="pln">complete</span><span class="pun">();</span><span class="pln">

  </span><span class="com">// unsubscribe function doesn't need to do anything in this</span><span class="pln">
  </span><span class="com">// because values are delivered synchronously</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">unsubscribe</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// Create a new Observable that will deliver the above </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><a href="api/animations/sequence" class="code-anchor"><span class="pln">sequence</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Observable</span><span class="pun">(</span><span class="pln">sequenceSubscriber</span><span class="pun">);</span><span class="pln">

</span><span class="com">// execute the Observable and print the result of each notification</span><span class="pln">
sequence</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">({</span><span class="pln">
  </span><span class="kwd">next</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">num</span><span class="pun">);</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  complete</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'</span><a href="" class="code-anchor"><span class="str">Finished</span></a><span class="str"> </span><a href="api/animations/sequence" class="code-anchor"><span class="str">sequence</span></a><span class="str">'</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="com">// Logs:</span><span class="pln">
</span><span class="com">// 1</span><span class="pln">
</span><span class="com">// 2</span><span class="pln">
</span><span class="com">// 3</span><span class="pln">
</span><span class="com">// </span><a href="" class="code-anchor"><span class="com">Finished</span></a><span class="com"> </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a></code>
    </pre></aio-code></code-example><p translation-result="on">如果要略微加强这个例子，我们可以创建一个用来发布事件的可观察对象。在这个例子中，订阅函数是用内联方式定义的。</p><p translation-origin="off">To take this example a little further, we can create an observable that publishes events. In this example, the subscriber function is defined inline.</p><code-example path="observables/src/creating.ts" region="fromevent" header="Create with custom fromEvent function" ng-version="9.0.0-rc.11"><div style="display:none">function fromEvent(target, <a href="api/core/HostListener#eventName" class="code-anchor">eventName</a>) { return new Observable((observer) =&gt; { const handler = (e) =&gt; observer.next(e); // Add the event handler to the target target.addEventListener(<a href="api/core/HostListener#eventName" class="code-anchor">eventName</a>, handler); return () =&gt; { // Detach the event handler from the target target.removeEventListener(<a href="api/core/HostListener#eventName" class="code-anchor">eventName</a>, handler); }; }); }</div><header class="ng-star-inserted">Create with custom fromEvent function</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from Create with custom fromEvent function">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">function</span><span class="pln"> fromEvent</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> </span><a href="api/core/HostListener#eventName" class="code-anchor"><span class="pln">eventName</span></a><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Observable</span><span class="pun">((</span><span class="pln">observer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> handler </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> observer</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="pln">e</span><span class="pun">);</span><span class="pln">

    </span><span class="com">// Add the event handler to the target</span><span class="pln">
    target</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><a href="api/core/HostListener#eventName" class="code-anchor"><span class="pln">eventName</span></a><span class="pun">,</span><span class="pln"> handler</span><span class="pun">);</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// Detach the event handler from the target</span><span class="pln">
      target</span><span class="pun">.</span><span class="pln">removeEventListener</span><span class="pun">(</span><a href="api/core/HostListener#eventName" class="code-anchor"><span class="pln">eventName</span></a><span class="pun">,</span><span class="pln"> handler</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">现在，你就可以使用这个函数来创建可发布 <code>keydown</code> 事件的可观察对象了：</p><p translation-origin="off">Now you can use this function to create an observable that publishes keydown events:</p><code-example path="observables/src/creating.ts" region="fromevent_use" header="Use custom fromEvent function" ng-version="9.0.0-rc.11"><div style="display:none">const ESC_KEY = 27; const nameInput = document.getElementById('name') as HTMLInputElement; const <a href="api/service-worker/SwPush#subscription" class="code-anchor">subscription</a> = fromEvent(nameInput, 'keydown') .subscribe((e: KeyboardEvent) =&gt; { if (e.keyCode === ESC_KEY) { nameInput.value = ''; } });</div><header class="ng-star-inserted">Use custom fromEvent function</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from Use custom fromEvent function">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">const</span><span class="pln"> ESC_KEY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">27</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> nameInput </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'name'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> </span><span class="typ">HTMLInputElement</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><a href="api/service-worker/SwPush#subscription" class="code-anchor"><span class="pln">subscription</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> fromEvent</span><span class="pun">(</span><span class="pln">nameInput</span><span class="pun">,</span><span class="pln"> </span><span class="str">'keydown'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">((</span><span class="pln">e</span><span class="pun">:</span><span class="pln"> </span><span class="typ">KeyboardEvent</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">keyCode </span><span class="pun">===</span><span class="pln"> ESC_KEY</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      nameInput</span><span class="pun">.</span><span class="kwd">value</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">});</span></code>
    </pre></aio-code></code-example><h2 id="multicasting" translation-result="on">多播<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#multicasting"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="multicasting">Multicasting<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#multicasting"><i class="material-icons">link</i></a></h2><p translation-result="on">典型的可观察对象会为每一个观察者创建一次新的、独立的执行。 当观察者进行订阅时，该可观察对象会连上一个事件处理器，并且向那个观察者发送一些值。当第二个观察者订阅时，这个可观察对象就会连上一个新的事件处理器，并独立执行一次，把这些值发送给第二个可观察对象。</p><p translation-origin="off">A typical observable creates a new, independent execution for each subscribed observer. When an observer subscribes, the observable wires up an event handler and delivers values to that observer. When a second observer subscribes, the observable then wires up a new event handler and delivers values to that second observer in a separate execution.</p><p translation-result="on">有时候，不应该对每一个订阅者都独立执行一次，你可能会希望每次订阅都得到同一批值 —— 即使是那些你已经发送过的。这在某些情况下有用，比如用来发送 <code><a href="api/platform-server/PlatformConfig#document" class="code-anchor">document</a></code> 上的点击事件的可观察对象。</p><p translation-origin="off">Sometimes, instead of starting an independent execution for each subscriber, you want each subscription to get the same values—even if values have already started emitting. This might be the case with something like an observable of clicks on the document object.</p><p translation-result="on"><em>多播</em>用来让可观察对象在一次执行中同时广播给多个订阅者。借助支持多播的可观察对象，你不必注册多个监听器，而是复用第一个（<code>next</code>）监听器，并且把值发送给各个订阅者。</p><p translation-origin="off"><em>Multicasting</em> is the practice of broadcasting to a list of multiple subscribers in a single execution. With a multicasting observable, you don't register multiple listeners on the document, but instead re-use the first listener and send values out to each subscriber.</p><p translation-result="on">当创建可观察对象时，你要决定你希望别人怎么用这个对象以及是否对它的值进行多播。</p><p translation-origin="off">When creating an observable you should determine how you want that observable to be used and whether or not you want to multicast its values.</p><p translation-result="on">来看一个从 1 到 3 进行计数的例子，它每发出一个数字就会等待 1 秒。</p><p translation-origin="off">Let’s look at an example that counts from 1 to 3, with a one-second delay after each number emitted.</p><code-example path="observables/src/multicasting.ts" region="delay_sequence" header="Create a delayed sequence" ng-version="9.0.0-rc.11"><div style="display:none">function sequenceSubscriber(observer) { const seq = [1, 2, 3]; let timeoutId; // Will run through an array of numbers, emitting one value // per second until it gets to the end of the array. function doSequence(arr, idx) { timeoutId = setTimeout(() =&gt; { observer.next(arr[idx]); if (idx === arr.length - 1) { observer.complete(); } else { doSequence(arr, ++idx); } }, 1000); } doSequence(seq, 0); // Unsubscribe should clear the timeout to stop execution return {unsubscribe() { clearTimeout(timeoutId); }}; } // Create a new Observable that will deliver the above <a href="api/animations/sequence" class="code-anchor">sequence</a> const <a href="api/animations/sequence" class="code-anchor">sequence</a> = new Observable(sequenceSubscriber); sequence.subscribe({ next(num) { console.log(num); }, complete() { console.log('<a href="" class="code-anchor">Finished</a> <a href="api/animations/sequence" class="code-anchor">sequence</a>'); } }); // Logs: // (at 1 second): 1 // (at 2 seconds): 2 // (at 3 seconds): 3 // (at 3 seconds): <a href="" class="code-anchor">Finished</a> <a href="api/animations/sequence" class="code-anchor">sequence</a></div><header class="ng-star-inserted">Create a delayed sequence</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from Create a delayed sequence">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">function</span><span class="pln"> sequenceSubscriber</span><span class="pun">(</span><span class="pln">observer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> seq </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">];</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> timeoutId</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// Will run through an array of numbers, emitting one value</span><span class="pln">
  </span><span class="com">// per second until it gets to the end of the array.</span><span class="pln">
  </span><span class="kwd">function</span><span class="pln"> doSequence</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">,</span><span class="pln"> idx</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    timeoutId </span><span class="pun">=</span><span class="pln"> setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      observer</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">[</span><span class="pln">idx</span><span class="pun">]);</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">idx </span><span class="pun">===</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        observer</span><span class="pun">.</span><span class="pln">complete</span><span class="pun">();</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        doSequence</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">,</span><span class="pln"> </span><span class="pun">++</span><span class="pln">idx</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  doSequence</span><span class="pun">(</span><span class="pln">seq</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">

  </span><span class="com">// Unsubscribe should clear the timeout to stop execution</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">unsubscribe</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    clearTimeout</span><span class="pun">(</span><span class="pln">timeoutId</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// Create a new Observable that will deliver the above </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><a href="api/animations/sequence" class="code-anchor"><span class="pln">sequence</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Observable</span><span class="pun">(</span><span class="pln">sequenceSubscriber</span><span class="pun">);</span><span class="pln">

sequence</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">({</span><span class="pln">
  </span><span class="kwd">next</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">num</span><span class="pun">);</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  complete</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'</span><a href="" class="code-anchor"><span class="str">Finished</span></a><span class="str"> </span><a href="api/animations/sequence" class="code-anchor"><span class="str">sequence</span></a><span class="str">'</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="com">// Logs:</span><span class="pln">
</span><span class="com">// (at 1 second): 1</span><span class="pln">
</span><span class="com">// (at 2 seconds): 2</span><span class="pln">
</span><span class="com">// (at 3 seconds): 3</span><span class="pln">
</span><span class="com">// (at 3 seconds): </span><a href="" class="code-anchor"><span class="com">Finished</span></a><span class="com"> </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a></code>
    </pre></aio-code></code-example><p translation-result="on">注意，如果你订阅了两次，就会有两个独立的流，每个流都会每秒发出一个数字。代码如下：</p><p translation-origin="off">Notice that if you subscribe twice, there will be two separate streams, each emitting values every second. It looks something like this:</p><code-example path="observables/src/multicasting.ts" region="subscribe_twice" header="Two subscriptions" ng-version="9.0.0-rc.11"><div style="display:none">// Subscribe starts the clock, and will emit after 1 second sequence.subscribe({ next(num) { console.log('1st subscribe: ' + num); }, complete() { console.log('1st <a href="api/animations/sequence" class="code-anchor">sequence</a> finished.'); } }); // After 1/2 second, subscribe again. setTimeout(() =&gt; { sequence.subscribe({ next(num) { console.log('2nd subscribe: ' + num); }, complete() { console.log('2nd <a href="api/animations/sequence" class="code-anchor">sequence</a> finished.'); } }); }, 500); // Logs: // (at 1 second): 1st subscribe: 1 // (at 1.5 seconds): 2nd subscribe: 1 // (at 2 seconds): 1st subscribe: 2 // (at 2.5 seconds): 2nd subscribe: 2 // (at 3 seconds): 1st subscribe: 3 // (at 3 seconds): 1st <a href="api/animations/sequence" class="code-anchor">sequence</a> finished // (at 3.5 seconds): 2nd subscribe: 3 // (at 3.5 seconds): 2nd <a href="api/animations/sequence" class="code-anchor">sequence</a> finished</div><header class="ng-star-inserted">Two subscriptions</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from Two subscriptions">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// Subscribe starts the clock, and will emit after 1 second</span><span class="pln">
sequence</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">({</span><span class="pln">
  </span><span class="kwd">next</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'1st subscribe: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> num</span><span class="pun">);</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  complete</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'1st </span><a href="api/animations/sequence" class="code-anchor"><span class="str">sequence</span></a><span class="str"> finished.'</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="com">// After 1/2 second, subscribe again.</span><span class="pln">
setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequence</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">({</span><span class="pln">
    </span><span class="kwd">next</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'2nd subscribe: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> num</span><span class="pun">);</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    complete</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'2nd </span><a href="api/animations/sequence" class="code-anchor"><span class="str">sequence</span></a><span class="str"> finished.'</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="lit">500</span><span class="pun">);</span><span class="pln">

</span><span class="com">// Logs:</span><span class="pln">
</span><span class="com">// (at 1 second): 1st subscribe: 1</span><span class="pln">
</span><span class="com">// (at 1.5 seconds): 2nd subscribe: 1</span><span class="pln">
</span><span class="com">// (at 2 seconds): 1st subscribe: 2</span><span class="pln">
</span><span class="com">// (at 2.5 seconds): 2nd subscribe: 2</span><span class="pln">
</span><span class="com">// (at 3 seconds): 1st subscribe: 3</span><span class="pln">
</span><span class="com">// (at 3 seconds): 1st </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a><span class="com"> finished</span><span class="pln">
</span><span class="com">// (at 3.5 seconds): 2nd subscribe: 3</span><span class="pln">
</span><span class="com">// (at 3.5 seconds): 2nd </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a><span class="com"> finished</span></code>
    </pre></aio-code></code-example><p translation-result="on">修改这个可观察对象以支持多播，代码如下：</p><p translation-origin="off">Changing the observable to be multicasting could look something like this:</p><code-example path="observables/src/multicasting.ts" region="multicast_sequence" header="Create a multicast subscriber" ng-version="9.0.0-rc.11"><div style="display:none">function multicastSequenceSubscriber() { const seq = [1, 2, 3]; // Keep track of each observer (one for every active <a href="api/service-worker/SwPush#subscription" class="code-anchor">subscription</a>) const observers = []; // Still a single timeoutId because there will only ever be one // set of values being generated, multicasted to each subscriber let timeoutId; // Return the subscriber function (runs when subscribe() // function is invoked) return (observer) =&gt; { observers.push(observer); // When this is the first <a href="api/service-worker/SwPush#subscription" class="code-anchor">subscription</a>, start the <a href="api/animations/sequence" class="code-anchor">sequence</a> if (observers.length === 1) { timeoutId = doSequence({ next(val) { // Iterate through observers and notify all subscriptions observers.forEach(obs =&gt; obs.next(val)); }, complete() { // Notify all complete callbacks observers.slice(0).forEach(obs =&gt; obs.complete()); } }, seq, 0); } return { unsubscribe() { // Remove from the observers array so it's no longer notified observers.splice(observers.indexOf(observer), 1); // If there's no more <a href="api/core/DebugNode#listeners" class="code-anchor">listeners</a>, do cleanup if (observers.length === 0) { clearTimeout(timeoutId); } } }; }; } // Run through an array of numbers, emitting one value // per second until it gets to the end of the array. function doSequence(observer, arr, idx) { return setTimeout(() =&gt; { observer.next(arr[idx]); if (idx === arr.length - 1) { observer.complete(); } else { doSequence(observer, arr, ++idx); } }, 1000); } // Create a new Observable that will deliver the above <a href="api/animations/sequence" class="code-anchor">sequence</a> const multicastSequence = new Observable(multicastSequenceSubscriber()); // Subscribe starts the clock, and begins to emit after 1 second multicastSequence.subscribe({ next(num) { console.log('1st subscribe: ' + num); }, complete() { console.log('1st <a href="api/animations/sequence" class="code-anchor">sequence</a> finished.'); } }); // After 1 1/2 seconds, subscribe again (should "miss" the first value). setTimeout(() =&gt; { multicastSequence.subscribe({ next(num) { console.log('2nd subscribe: ' + num); }, complete() { console.log('2nd <a href="api/animations/sequence" class="code-anchor">sequence</a> finished.'); } }); }, 1500); // Logs: // (at 1 second): 1st subscribe: 1 // (at 2 seconds): 1st subscribe: 2 // (at 2 seconds): 2nd subscribe: 2 // (at 3 seconds): 1st subscribe: 3 // (at 3 seconds): 1st <a href="api/animations/sequence" class="code-anchor">sequence</a> finished // (at 3 seconds): 2nd subscribe: 3 // (at 3 seconds): 2nd <a href="api/animations/sequence" class="code-anchor">sequence</a> finished</div><header class="ng-star-inserted">Create a multicast subscriber</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from Create a multicast subscriber">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">function</span><span class="pln"> multicastSequenceSubscriber</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> seq </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">];</span><span class="pln">
  </span><span class="com">// Keep track of each observer (one for every active </span><a href="api/service-worker/SwPush#subscription" class="code-anchor"><span class="com">subscription</span></a><span class="com">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> observers </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">
  </span><span class="com">// Still a single timeoutId because there will only ever be one</span><span class="pln">
  </span><span class="com">// set of values being generated, multicasted to each subscriber</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> timeoutId</span><span class="pun">;</span><span class="pln">

  </span><span class="com">// Return the subscriber function (runs when subscribe()</span><span class="pln">
  </span><span class="com">// function is invoked)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">observer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    observers</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">observer</span><span class="pun">);</span><span class="pln">
    </span><span class="com">// When this is the first </span><a href="api/service-worker/SwPush#subscription" class="code-anchor"><span class="com">subscription</span></a><span class="com">, start the </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">observers</span><span class="pun">.</span><span class="pln">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      timeoutId </span><span class="pun">=</span><span class="pln"> doSequence</span><span class="pun">({</span><span class="pln">
        </span><span class="kwd">next</span><span class="pun">(</span><span class="pln">val</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="com">// Iterate through observers and notify all subscriptions</span><span class="pln">
          observers</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">obs </span><span class="pun">=&gt;</span><span class="pln"> obs</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="pln">val</span><span class="pun">));</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        complete</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="com">// Notify all complete callbacks</span><span class="pln">
          observers</span><span class="pun">.</span><span class="pln">slice</span><span class="pun">(</span><span class="lit">0</span><span class="pun">).</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">obs </span><span class="pun">=&gt;</span><span class="pln"> obs</span><span class="pun">.</span><span class="pln">complete</span><span class="pun">());</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln"> seq</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      unsubscribe</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// Remove from the observers array so it's no longer notified</span><span class="pln">
        observers</span><span class="pun">.</span><span class="pln">splice</span><span class="pun">(</span><span class="pln">observers</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="pln">observer</span><span class="pun">),</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
        </span><span class="com">// If there's no more </span><a href="api/core/DebugNode#listeners" class="code-anchor"><span class="com">listeners</span></a><span class="com">, do cleanup</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">observers</span><span class="pun">.</span><span class="pln">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          clearTimeout</span><span class="pun">(</span><span class="pln">timeoutId</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// Run through an array of numbers, emitting one value</span><span class="pln">
</span><span class="com">// per second until it gets to the end of the array.</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> doSequence</span><span class="pun">(</span><span class="pln">observer</span><span class="pun">,</span><span class="pln"> arr</span><span class="pun">,</span><span class="pln"> idx</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    observer</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">[</span><span class="pln">idx</span><span class="pun">]);</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">idx </span><span class="pun">===</span><span class="pln"> arr</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      observer</span><span class="pun">.</span><span class="pln">complete</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      doSequence</span><span class="pun">(</span><span class="pln">observer</span><span class="pun">,</span><span class="pln"> arr</span><span class="pun">,</span><span class="pln"> </span><span class="pun">++</span><span class="pln">idx</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// Create a new Observable that will deliver the above </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a><span class="pln">
</span><span class="kwd">const</span><span class="pln"> multicastSequence </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Observable</span><span class="pun">(</span><span class="pln">multicastSequenceSubscriber</span><span class="pun">());</span><span class="pln">

</span><span class="com">// Subscribe starts the clock, and begins to emit after 1 second</span><span class="pln">
multicastSequence</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">({</span><span class="pln">
  </span><span class="kwd">next</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'1st subscribe: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> num</span><span class="pun">);</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  complete</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'1st </span><a href="api/animations/sequence" class="code-anchor"><span class="str">sequence</span></a><span class="str"> finished.'</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="com">// After 1 1/2 seconds, subscribe again (should "miss" the first value).</span><span class="pln">
setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  multicastSequence</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">({</span><span class="pln">
    </span><span class="kwd">next</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'2nd subscribe: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> num</span><span class="pun">);</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    complete</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'2nd </span><a href="api/animations/sequence" class="code-anchor"><span class="str">sequence</span></a><span class="str"> finished.'</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="lit">1500</span><span class="pun">);</span><span class="pln">

</span><span class="com">// Logs:</span><span class="pln">
</span><span class="com">// (at 1 second): 1st subscribe: 1</span><span class="pln">
</span><span class="com">// (at 2 seconds): 1st subscribe: 2</span><span class="pln">
</span><span class="com">// (at 2 seconds): 2nd subscribe: 2</span><span class="pln">
</span><span class="com">// (at 3 seconds): 1st subscribe: 3</span><span class="pln">
</span><span class="com">// (at 3 seconds): 1st </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a><span class="com"> finished</span><span class="pln">
</span><span class="com">// (at 3 seconds): 2nd subscribe: 3</span><span class="pln">
</span><span class="com">// (at 3 seconds): 2nd </span><a href="api/animations/sequence" class="code-anchor"><span class="com">sequence</span></a><span class="com"> finished</span></code>
    </pre></aio-code></code-example><div class="alert is-helpful"><p translation-result="on">虽然支持多播的可观察对象需要做更多的准备工作，但对某些应用来说，这非常有用。稍后我们会介绍一些简化多播的工具，它们让你能接收任何可观察对象，并把它变成支持多播的。</p><p translation-origin="off">Multicasting observables take a bit more setup, but they can be useful for certain applications. Later we will look at tools that simplify the process of multicasting, allowing you to take any observable and make it multicasting.</p></div><h2 id="error-handling" translation-result="on">错误处理<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#error-handling"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="error-handling">Error handling<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/observables#error-handling"><i class="material-icons">link</i></a></h2><p translation-result="on">由于可观察对象会异步生成值，所以用 <code>try/catch</code> 是无法捕获错误的。你应该在观察者中指定一个 <code>error</code> 回调来处理错误。发生错误时还会导致可观察对象清理现有的订阅，并且停止生成值。可观察对象可以生成值（调用 <code>next</code> 回调），也可以调用 <code>complete</code> 或 <code>error</code> 回调来主动结束。</p><p translation-origin="off">Because observables produce values asynchronously, try/catch will not effectively catch errors. Instead, you handle errors by specifying an <code>error</code> callback on the observer. Producing an error also causes the observable to clean up subscriptions and stop producing values. An observable can either produce values (calling the <code>next</code> callback), or it can complete, calling either the <code>complete</code> or <code>error</code> callback.</p><code-example ng-version="9.0.0-rc.11"><div style="display:none">myObservable.subscribe({ next(num) { console.log('Next num: ' + num)}, error(err) { console.log('Received an errror: ' + err)} });</div><aio-code><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">myObservable</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">({</span><span class="pln">
  </span><span class="kwd">next</span><span class="pun">(</span><span class="pln">num</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Next num: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> num</span><span class="pun">)},</span><span class="pln">
  error</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Received an errror: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> err</span><span class="pun">)}</span><span class="pln">
</span><span class="pun">});</span></code>
    </pre></aio-code></code-example><p translation-result="on">在稍后的小节中会对错误处理（特别是从错误中的恢复）做更详细的讲解。</p><p translation-origin="off">Error handling (and specifically recovering from an error) is covered in more detail in a later section.</p></div></div></aio-doc-viewer></main></mat-sidenav-content></mat-sidenav-container><div class="toc-container no-print ng-star-inserted"><aio-lazy-ce selector="aio-toc"><aio-toc ng-version="9.0.0-rc.11"><div class="toc-inner no-print collapsed ng-star-inserted"><ul class="toc-list"><li class="h1 ng-star-inserted active" title="可观察对象（Observable）"><a href="guide/observables#observables">可观察对象（Observable）</a></li><li class="h2 ng-star-inserted" title="基本用法和词汇"><a href="guide/observables#basic-usage-and-terms">基本用法和词汇</a></li><li class="h2 ng-star-inserted" title="定义观察者"><a href="guide/observables#defining-observers">定义观察者</a></li><li class="h2 ng-star-inserted" title="订阅"><a href="guide/observables#subscribing">订阅</a></li><li class="h2 ng-star-inserted" title="创建可观察对象"><a href="guide/observables#creating-observables">创建可观察对象</a></li><li class="h2 ng-star-inserted" title="多播"><a href="guide/observables#multicasting">多播</a></li><li class="h2 ng-star-inserted" title="错误处理"><a href="guide/observables#error-handling">错误处理</a></li></ul></div></aio-toc></aio-lazy-ce></div><footer class="no-print"><aio-footer><div class="grid-fluid"><div class="footer-block ng-star-inserted"><h3>资源</h3><ul><li class="ng-star-inserted"><a class="link" href="about" title="Angular 贡献者。">关于</a></li><li class="ng-star-inserted"><a class="link" href="resources" title="网络上的 Angular 工具、培训、博客等">资源列表</a></li><li class="ng-star-inserted"><a class="link" href="presskit" title="我们的联系方式、LOGO 和品牌">宣传资料</a></li><li class="ng-star-inserted"><a class="link" href="https://blog.angular.io/" title="Angular 官方博客">博客</a></li><li class="ng-star-inserted"><a class="link" href="analytics" title="Angular 使用情况分析">使用情况分析</a></li></ul></div><div class="footer-block ng-star-inserted"><h3>帮助</h3><ul><li class="ng-star-inserted"><a class="link" href="https://stackoverflow.com/questions/tagged/angular" title="Stack Overflow: 这里的社区会回答你关于 Angular 的技术问题">Stack Overflow</a></li><li class="ng-star-inserted"><a class="link" href="https://gitter.im/angular/angular" title="和老鸟聊 Angular">Gitter</a></li><li class="ng-star-inserted"><a class="link" href="https://github.com/angular/angular/issues" title="在 github 上报告问题和建议。">报告问题</a></li><li class="ng-star-inserted"><a class="link" href="https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md" title="让我们彼此尊重">行为规范</a></li></ul></div><div class="footer-block ng-star-inserted"><h3>社区</h3><ul><li class="ng-star-inserted"><a class="link" href="events" title="Angular events around the world.">活动</a></li><li class="ng-star-inserted"><a class="link" href="http://www.meetup.com/topics/angularjs/" title="参加聚会，向别的开发人员学习">聚会</a></li><li class="ng-star-inserted"><a class="link" href="https://twitter.com/angular" title="Twitter">Twitter</a></li><li class="ng-star-inserted"><a class="link" href="https://github.com/angular/angular" title="GitHub">GitHub</a></li><li class="ng-star-inserted"><a class="link" href="contribute" title="向 Angular 做贡献">做贡献</a></li></ul></div><div class="footer-block ng-star-inserted"><h3>多语言</h3><ul><li class="ng-star-inserted"><a class="link" href="https://angular.io/" title="English Version.">English Version</a></li><li class="ng-star-inserted"><a class="link" href="https://angular.tw/" title="正體中文版">正體中文版</a></li><li class="ng-star-inserted"><a class="link" href="https://angular.jp/" title="日本語版">日本語版</a></li><li class="ng-star-inserted"><a class="link" href="https://angular.kr/" title="한국어">한국어</a></li></ul></div></div><p>Super-powered by Google ©2010-2020. 代码授权方式：<a href="license" title="License text">MIT-style License</a>. 文档授权方式：<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.</p><p>当前版本：9.0.1-build.109+sha.7a49faba.</p></aio-footer></footer><div class="cdk-visually-hidden ng-star-inserted"><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color" aria-hidden="true">&nbsp;</mat-icon></div></aio-shell><noscript><div class="background-sky hero"></div><section id="intro" style="text-shadow:1px 1px #1976d2"><div class="hero-logo"><img src="assets/images/logos/angular/angular.svg" width="250" height="250" alt="Angular"></div><div class="homepage-container"><div class="hero-headline">一套框架，多种平台<br>移动 &amp; 桌面</div></div></section><h2 style="color:red;margin-top:40px;position:relative;text-align:center;text-shadow:1px 1px #fafafa"><b><i>该网站需要浏览器支持 JavaScript</i></b></h2></noscript><script src="runtime-es2015.811b066977719df5af39.js" type="module"></script><script src="runtime-es5.811b066977719df5af39.js" nomodule="" defer=""></script><script src="polyfills-es5.1494ca908613f3429457.js" nomodule="" defer=""></script><script src="polyfills-es2015.9057a05c650bf60ecbf4.js" type="module"></script><script src="main-es2015.4e9aa34b562bab1382ab.js" type="module"></script><script src="main-es5.4e9aa34b562bab1382ab.js" nomodule="" defer=""></script><div class="cdk-live-announcer-element cdk-visually-hidden" aria-atomic="true" aria-live="polite"></div></body></html>